package com.java.actual.fivechess;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Shape;
import java.awt.Stroke;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.Ellipse2D;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

import javax.swing.JOptionPane;
import javax.swing.JPanel;

/**
 * 棋盘中间的网格图形，覆盖了该类的paintComponent()方法，重新绘制图形。
 * @author Administrator
 *
 */
public class GraphicPanel extends JPanel{
	private boolean isBlack=true;//当前下子是否是黑方
	private char[][] allChess;//保存所有棋子的数组
	
	private int boardX=-1;//最后一次有效落子在棋盘的x，y坐标
	private int boardY=-1;
	
	public static final int ROW_NUM=16;//行数
	public static final int COL_NUM=16;//列数
	
	public static final int LEFT_BORDER=20;//左边界
	public static final int RIGTH_BORDER=20;//右边界
	public static final int UP_BORDER=20;//上边界
	public static final int DOWN_BORDER=100;//下边界
	
	public static final int ROW_GAP=40;//行间隙
	public static final int COL_GAP=40;//列间隙
	
	public static final int ChessRadio=15;//棋子半径
	
	public GraphicPanel(){
		allChess=new char[ROW_NUM][COL_NUM];
		for(int i=0;i<allChess.length;i++){//给旗子数组实例化
			for(int j=0;j<allChess[i].length;j++){
				allChess[i][j]='*';//初始时都赋为‘*’
			}
		}
		
		ChessBoard.label.setText((isBlack?"黑":"白")+"方请下子...");	
		
		addMouseListener(new MouseAdapter(){//给该面板添加鼠标事件监听
			public void mouseClicked(MouseEvent e) {
				int button=e.getButton();
				if(button!=MouseEvent.BUTTON1){//如果不是鼠标左键点击
					return;//则不做任何处理
				}
				int x=e.getX();//获得鼠标点击位置的x，y坐标
				int y=e.getY();
				
				//如果鼠标点击点没有发生在棋盘的有效位置
				if(x<LEFT_BORDER/2 || x> LEFT_BORDER+(COL_NUM-1)*COL_GAP+RIGTH_BORDER/2
						|| y<UP_BORDER/2 || y>UP_BORDER+(ROW_NUM-1)*ROW_GAP+DOWN_BORDER/2){
				
					ChessBoard.label.setText("无效位置！");
					return;//则不做任何处理
				}
				
				
				//将鼠标点击点的x，y坐标换算成棋盘上的x，y坐标。
				int boardX=Math.round((float)(x-LEFT_BORDER)/ROW_GAP);
				int boardY=Math.round((float)(y-UP_BORDER)/COL_GAP);
				
				//如果该位置上有棋子
				if(allChess[boardY][boardX]!='*'){
					ChessBoard.label.setText("该位置有棋子");
					return;//则不做任何处理
				}
				//将棋盘上该位置设置为指定棋子
				allChess[boardY][boardX]=isBlack?'@':'O';
				
				GraphicPanel.this.boardX=boardX;//保存最后一次有效落子的坐标
				GraphicPanel.this.boardY=boardY;
				
				//重画棋盘
				GraphicPanel.this.repaint();
				
				if(wasWin()){
					String mesg=(isBlack?"黑":"白")+"方获胜！";
					ChessBoard.label.setText(mesg);
					JOptionPane.showMessageDialog(GraphicPanel.this,mesg);
					clear();
					return;
				}
				//改变下棋方
				isBlack=!isBlack;
				ChessBoard.label.setText((isBlack?"黑":"白")+"方请下子...");	
			}
		});
	}
	
	public  boolean wasWin(){
		return wasWinAtV()||wasWinAtH()||wasWinAtLD()||wasWinAtRD();
	}
	
	private  boolean wasWinAtV(){
		char ch=isBlack?'@':'O';
		int i=boardX;
		while(i>=0 && allChess[boardY][i]==ch){//向左找到第一个不是ch的字符
			i--;
		}
		int num=0;
		i++;
		while(i<allChess.length && allChess[boardY][i]==ch){
			num++;
			i++;
		}
		return num>=5;
		
	}
	
	private  boolean wasWinAtH(){
		char ch=isBlack?'@':'O';
		int i=boardY;
		while(i>=0 && allChess[i][boardX]==ch){//向左找到第一个不是ch的字符
			i--;
		}
		int num=0;
		i++;
		while(i<allChess.length && allChess[i][boardX]==ch){
			num++;
			i++;
		}
		return num>=5;
	}
	
	private  boolean wasWinAtLD(){
		char ch=isBlack?'@':'O';
		int i=boardY;
		int j=boardX;
		while(i>=0 && j<allChess.length && allChess[i][j]==ch){//向左找到第一个不是ch的字符
			i--;
			j++;
		}
		int num=0;
		i++;
		j--;
		while(i<allChess.length && j>=0 && allChess[i][j]==ch){
			num++;
			i++;
			j--;
		}
		return num>=5;
	}
	
	private  boolean wasWinAtRD(){
		char ch=isBlack?'@':'O';
		int i=boardY;
		int j=boardX;
		while(i>=0 && j>=0 && allChess[i][j]==ch){//向左找到第一个不是ch的字符
			i--;
			j--;
		}
		int num=0;
		i++;
		j++;
		while(i<allChess.length && j<allChess.length && allChess[i][j]==ch){
			num++;
			i++;
			j++;
		}
		return num>=5;
	}
	
	
	/**
	 * 该方法在获胜后重新绘制棋盘，并初始化参数。
	 *
	 */
	public void clear(){
		boardX=-1;
		boardY=-1;
		for(int i=0;i<allChess.length;i++){
			for(int j=0;j<allChess[i].length;j++){
				allChess[i][j]='*';//初始时都赋为‘*’
			}
		}
		isBlack=true;
//		重画棋盘
		repaint();
		ChessBoard.label.setText((isBlack?"黑":"白")+"方请下子...");	
	}
	
	/**
	 * 把当前棋盘状态保存到指定的文件中！
	 * @param f
	 */
	public boolean saveToFile(File f){
		//1,建立一个FileOutputStream
		FileOutputStream fos=null;
		try {
			fos=new FileOutputStream(f);
			for(int i=0;i<allChess.length;i++){
				for(int j=0;j<allChess[i].length;j++){
					if(i==boardY && j==boardX){
						fos.write(isBlack?'W':'B');
					}else{
						fos.write(allChess[i][j]);
					}
				}
			}
		} catch (IOException e) {
			e.printStackTrace();
			return false;
		}finally{
			if(fos!=null)try{fos.close();}catch(IOException e){}
		}

		return true;
	}
	
	
	/**
	 * 从指定的文件中装载棋盘信息
	 * @param f
	 */
	public boolean loadFromFile(File f){
		FileInputStream fis=null;
		try {
			fis=new FileInputStream(f);
			for(int i=0;i<allChess.length;i++){
				for(int j=0;j<allChess[i].length;j++){
					char c=(char)fis.read();
					if(c!='*' && c!='O' && c!='@' && c!='W' && c!='B'){
						return false;
					}
					if(c=='B'){
						allChess[i][j]='@';
						boardX=j;
						boardY=i;
						isBlack=false;
					}else if(c=='W'){
						allChess[i][j]='O';
						boardX=j;
						boardY=i;
						isBlack=true;
					}else{
						allChess[i][j]=c;
					}
				}
			}
		} catch (IOException e) {
			e.printStackTrace();
			return false;
		}finally{
			if(fis!=null)try{fis.close();}catch(IOException e){}
		}
		
		this.repaint();
		return true;
	}

	
	@Override
	
	/**
	 * 该方法为覆盖父类的方法，每次重画棋盘时系统会自动调用该方法。
	 */
	public void paintComponent(Graphics g){
		super.paintComponent(g);
		//定义画笔类型
		Stroke stroke=new BasicStroke(2.0f);
		
		Graphics2D g2=(Graphics2D)g;
		g2.setStroke(stroke);
		
		//循环画出若干水平平行直线
		for(int i=0;i<ROW_NUM;i++){
			g2.drawLine(LEFT_BORDER,UP_BORDER+ROW_GAP*i,
					(COL_NUM-1)*COL_GAP+LEFT_BORDER,UP_BORDER+ROW_GAP*i);
		}
		
		//循环画出若干垂直平行直线
		for(int i=0;i<COL_NUM;i++){
			g2.drawLine(LEFT_BORDER+COL_GAP*i,UP_BORDER,
					LEFT_BORDER+COL_GAP*i,(ROW_NUM-1)*ROW_GAP+UP_BORDER);
		}
		
		
		//循环读取allChess数组，根据数组的内容画出每一个棋子。
		for(int i=0;i<allChess.length;i++){
			for(int j=0;j<allChess[i].length;j++){
				if(allChess[i][j]=='*'){
					continue;
				}
				Shape s=new Ellipse2D.Double(j*COL_GAP+LEFT_BORDER-ChessRadio,
						i*ROW_GAP+UP_BORDER-ChessRadio,ChessRadio*2,ChessRadio*2); 
				g2.setColor(Color.BLACK);
				g2.draw(s);
				if(allChess[i][j]=='@'){
					g2.setColor(Color.BLACK);
				}else{
					g2.setColor(Color.WHITE);
				}
				g2.fill(s);
			}
		}
		
		if(boardX!=-1){//在最后一次有效落点位置画一个红‘X’，用以标识。
			g2.setColor(Color.RED);
			g2.drawLine(boardX*ROW_GAP+LEFT_BORDER-5,boardY*COL_GAP+UP_BORDER-5,boardX*ROW_GAP+LEFT_BORDER+5,boardY*COL_GAP+UP_BORDER+5);
			g2.drawLine(boardX*ROW_GAP+LEFT_BORDER+5,boardY*COL_GAP+UP_BORDER-5,boardX*ROW_GAP+LEFT_BORDER-5,boardY*COL_GAP+UP_BORDER+5);
		}
		
	}
}
